<template>
  <div>
    <el-card class="box-card">
      <!-- 卡片顶部的添加品牌的按钮 -->
      <el-button type="primary" size="default" @click="addTrademark" icon="Plus">添加品牌</el-button>
      <!-- 表格组件: 用户展示已有的品牌 -->
      <!-- 
      table的属性中
      border: 是否带有纵向边框

      el-table-column
      label 设置标题
      width 设置宽度
      align 设置这一列的对齐方式
    -->
      <el-table :data="trademarkArr" style="margin: 10px 0px" border>
        <el-table-column label="序号" width="80px" align="center" type="index" />
        <!-- table-column:默认展示数据用的是div，也可以使用插槽传结构
          如果当你展示字段想要div标签包裹就可以直接使用 prop="字段名" 即可，
          如果当你展示字段想要别的标签包裹那么就可以使用插槽的方式
        -->
        <!-- <el-table-column label="品牌名称">
          <template #="{ row }">
            <pre style="color: brown;">{{ row.tmName }}</pre>
          </template> 
        </el-table-column> -->
        <el-table-column label="品牌名称" prop="tmName" />
        <el-table-column label="品牌LOGO">
          <template #="{ row }">
            <el-image style="width: 100px; height: 100px" :src="row.logoUrl" fit="fill" loading="lazy"></el-image>
          </template>
        </el-table-column>
        <el-table-column label="品牌操作">
          <template #="{ row }">
            <el-button type="primary" size="small" @click="updateTrademark(row)" icon="Edit">编辑</el-button>
            <!-- <el-button type="danger" size="small" @click="" icon="Delete">删除</el-button> -->

            <el-popconfirm :title="`你确认要删除品牌${row.tmName}吗`" width="250px" icon="Delete"
              @confirm="removeTradeMark(row.id)">
              <template #reference>
                <el-button type="danger" size="small" icon="Delete">删除</el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 对话框组件:在添加品牌与修改已有品牌的业务时候使用结构 -->
    <!-- 
      v-model="dialogFormVisible" 用来控制对话框的显示与隐藏 true 显示 false 隐藏
      title: 设置对话框标题
      label-width: el-form-item的属性，设置标签宽度
    -->
    <el-dialog v-model="dialogFormVisible" :title="dialogAction">
      <el-form style="width: 80%" :model="trademarkParams" :rules="rules" ref="formRef">
        <el-form-item label="品牌名称" label-width="100px" prop="tmName">
          <el-input placeholder="请您输入品牌名称" v-model="trademarkParams.tmName" />
        </el-form-item>
        <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
          <!-- 
            action: 文件上传的后端接口，注意这里需要在接口前面加上/api,其他的请求我们可以通过浏览器的network也可以看出，都是携带/api的，如果不加/api，代理服务器不会帮你干活的，还要注意请求的方式要跟后端允许的接口保持一致。比如获取品牌信息 http://localhost:5173/api/admin/product/baseTrademark/2/3
            show-file-list：是否显示文件上传的列表
            on-success	文件上传成功时的钩子
          -->
          <el-upload class="avatar-uploader" action="/api/admin/product/fileUpload" :show-file-list="false"
            :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
            <!-- 如果上传成功后，服务器返回图片的url地址，trademarkParams.logoUrl有值那么就显示出图片，下面icon图标Plus就不显示；
               如果用户刚开始没有上传，trademarkParams.logoUrl的值为空，那么就显示下面的icon Plus图标
          -->
            <img v-if="trademarkParams.logoUrl" :src="trademarkParams.logoUrl" class="avatar" />
            <el-icon v-else class="avatar-uploader-icon">
              <Plus />
            </el-icon>
          </el-upload>
        </el-form-item>
      </el-form>
      <!-- 具名插槽:footer -->
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancal">取消</el-button>
          <el-button type="primary" @click="confirm">确定</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 分页器组件 
    pagination
      v-model:current-page 分页器当前的页码
      v-model:page-size 设置每页显示条目个数
      page-sizes 每页显示个数选择器的选项设置 object [10, 20, 30, 40, 50, 100]
      small 是否使用小型分页样式(表示整体样式的大小)
      disabled 是否禁用分页，这里我们不禁用
      background 是否为分页按钮添加背景色
      layout 组件布局,子组件名用逗号分隔 string prev, pager, next, jumper, ->, total()
      layout 简单点来说官方默认把分页面拆分为上面6个子组件，而layout可以调整他们的布局顺序，箭头的函数把箭头指向的组件 向侧边顶到头
   -->
    <el-pagination :pager-count="5" v-model:current-page="pageNo" v-model:page-size="limitPageSize"
      :page-sizes="[3, 5, 7, 9]" :background="true" layout="prev, pager, next, jumper, ->, sizes, total" :total="total" />
  </div>
</template>
<script setup lang="ts">
// 引入组合式API函数ref
import { ref, reactive, onMounted, watch } from 'vue'
import {
  reqHasTradeMark,
  reqAddOrUpdateTradeMark,
  reqDeleteTradeMark,
} from '@/api/product/trademark'
// 引入类型
import type {
  TradeMarkResponseData,
  Record,
  TradeMark,
} from '@/api/product/trademark/type'
import { ElMessage, UploadProps } from 'element-plus/lib/components/index.js'
// 当前页码
let pageNo = ref<number>(1)
// 设置每页显示条目个数
let limitPageSize = ref<number>(3)
// 存储已有数据的总数
let total = ref<number>(0)
// 存储已有品牌的数据
let trademarkArr = ref<Record>([])
// 控制对话框的显示与隐藏
let dialogFormVisible = ref<boolean>(false)
// 定义收集新增品牌的数据
let trademarkParams = reactive<TradeMark>({
  tmName: '',
  logoUrl: '',
})
// 
// 定义: 添加品牌|修改品牌 的行为
let dialogAction = ref<string>('')

// 获取el-form表单实例对象
let formRef = ref()

// 获取已有品牌的数据封装成一个函数
const getTradeMark = async () => {
  let result: TradeMarkResponseData = await reqHasTradeMark(
    pageNo.value,
    limitPageSize.value,
  )
  if (result.code == 200) {
    total.value = result.data.total
    trademarkArr.value = result.data.records
  }
}

// 组件挂载完毕，发送请求。获取默认第一页，每页有三条数据
onMounted(() => {
  getTradeMark()
})

// @size-change	 @current-change 这两个为官方目前自定制的事件，不推荐使用，官网推荐直接使用v-model
// 分页器页码发生变化的时候会触发（这里我们使用watch）
watch(pageNo, () => {
  // 当前页码发生变化的时候再次发请求获取已有品牌数据展示
  getTradeMark()
})

// 当下拉菜单(3条/每页|5条/每页)发生变化的时候触发
watch(limitPageSize, () => {
  // 页面需要跳到第1页？
  // 因为比如总共有27页，每页显示3条数据，假如你当前在第9页，如果你把每页显示3条数据改为每页显示9条数据，那么就不存在第9页了。所以我们在改变页数的时候要把页面设置为1
  pageNo.value = 1
  // 当前页码发生变化的时候再次发请求获取已有品牌数据展示
  getTradeMark()
})

// 添加品牌回调函数
const addTrademark = () => {
  dialogFormVisible.value = true
  dialogAction.value = '添加品牌'
  // 清空已经存在的数据
  trademarkParams.id = 0  // 这一点尤为重要，如果不加这一条，那么在修改完数据之后，再点击添加，其实本质上还是修改，因为id存在，还是之前的id。而id是否存在是我们判断是新增还是修改的关键。
  trademarkParams.tmName = ''
  trademarkParams.logoUrl = ''
  // 在添加品牌之前，清除验证信息的两种方式
  // 第一种：利用ES6的语法，添加信息之后，如果有form.value有值，就表示已经生成了dialog的对话框中form，就需要清理验证信息；否则证明是第一次添加无需任何操作
  formRef.value?.clearValidate('tmName')
  formRef.value?.clearValidate('logoUrl')
  // 第二种：
  // nextTick(()=>{
  //   formRef.value.clearValidate('tmName')
  //   formRef.value.clearValidate('logoUrl')
  // })
}

// 修改品牌回调函数
// row: 为当前已有的品牌
const updateTrademark = (row: TradeMark) => {
  // 清空校验规则的错误提示信息
  formRef.value?.clearValidate('tmName')
  formRef.value?.clearValidate('logoUrl')
  // nextTick(()=>{
  //   formRef.value.clearValidate('tmName')
  //   formRef.value.clearValidate('logoUrl')
  // })
  dialogFormVisible.value = true
  dialogAction.value = '修改品牌'
  // 收集id的信息，后端接口就是通过是否有id来判断是修改还是新增
  // trademarkParams.id = row.id
  // // 展示已有品牌的数据
  // trademarkParams.tmName = row.tmName
  // trademarkParams.logoUrl = row.logoUrl

  // 上面的三行可以用ES6语法的一行搞定
  Object.assign(trademarkParams, row)
}

// 对话框取消
const cancal = () => {
  dialogFormVisible.value = false
}
// 对话框确认
const confirm = async () => {
  // 在发请求前对所有的表单进行校验,全部检验通过之后再往下执行
  await formRef.value.validate()

  const result: any = await reqAddOrUpdateTradeMark(trademarkParams)
  // 1.关闭对话框
  dialogFormVisible.value = false
  // 添加|修改 品牌成功
  if (result.code == 200) {
    // 2. 添加提示信息
    ElMessage({
      type: 'success',
      message: `${dialogAction.value}成功`
    })
    // 3. 再次发起请求，重新获取全部品牌的数据，把新添加的品牌刷出来
    getTradeMark()
  } else {
    // 添加|修改 品牌失败
    ElMessage({
      type: 'error',
      message: `${dialogAction.value}失败: ${result.data}`
    })
  }
}

// 上传文件组件-在上传文件之前触发调用的钩子函数
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile: any) => {
  // 文件上传成功之前触发，在文件上传之前可以约束文件的类型和大小
  // 要求文件的类型必须是：jpg|png|gif，文件大小必须小于2M
  if (rawFile.type != 'image/png' && rawFile.type !== 'image/jpeg' && rawFile.type !== 'image/gif') {
    ElMessage.error('上传文件格式必须是 PNG | JPEG | GIF')
    return false // 表示不允许上传
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('上传图片的大小不能超过2MB!')
    return false
  }
  return true // 表示允许上传
}

//  文件上传成功之后的钩子函数
const handleAvatarSuccess: UploadProps['onSuccess'] = (response: any, _: any) => {
  // response 为上传图片post请求服务器返回的数据
  // uploadFile 包含了response，还有更详细的数据，比如图片的大小等
  if (response.code == 200) {
    trademarkParams.logoUrl = response.data // 收集上传图片的地址
    // 图片上传成功后，清除对应的图片校验结果
    formRef.value.clearValidate('logoUrl')
  } else {
    ElMessage({
      type: 'error',
      message: `图片上传失败: ${response.message}`
    })
  }
}

// 品牌名称自定义校验规则的方法
const validatorTmName = (_: any, value: any, callback: any) => {
  if (value.trim().length >= 2) {
    callback()
  } else {
    callback(new Error('品牌名称不能少了两个字符'))
  }
}

// 品牌LOGO的自定义校验规则方法
const validatorLogoUrl = (_: any, value: any, callback: any) => {
  // 当前在提交按钮前触发表单全部按钮进行表单验证(formRef.value.validate())时，这里的value的值就是图片上传后的地址
  if (value.trim()) {
    callback()
  } else {
    callback(new Error('品牌LOGO图片务必上传'))
  }
}

// 定义表单校验规则对象
const rules = {
  tmName: [
    // required: true, 文本框会出现一个五角星
    { required: true, trigger: 'blur', validator: validatorTmName },
  ],
  // 对上传的文件返回的Url，无法通过trigger进行触发校验
  logoUrl: [
    { required: true, validator: validatorLogoUrl }
  ]
}

// 气泡确认框确认按钮的回调
const removeTradeMark = async (id: number) => {
  let result = await reqDeleteTradeMark(id)
  if (result.code == 200) {
    ElMessage({
      type: 'success',
      message: `删除id为${id}的品牌成功`
    })
    // 再次请求已有商品的信息
    getTradeMark()
  } else {
    ElMessage({
      type: 'error',
      message: `删除id为${id}的品牌失败`
    })
  }
}
</script>
<script lang="ts">
export default {
  name: 'ProductTradeMark',
}
</script>

<style>
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}

.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>
